use std::any::{type_name, Any};
use std::collections::HashMap;
use bytes::{Buf, BufMut, BytesMut};
use log::info;
use rpc::codec::json_codec::RpcJsonCodec;

struct Dto<T> {
    data: T,
}

fn call_dto<T: 'static>(dto: Dto<T>) {
    let any: Box<dyn Any> = Box::new(dto.data);
    if any.is::<i32>() {
        let value = any.downcast::<i32>().unwrap();
        info!("i32 value: {}", value);
    } else if any.is::<Vec<i32>>() {
        let value = any.downcast::<Vec<i32>>().unwrap();
        info!("Vec<i32> value: {:?}", value);
    }
}

fn call_dto1<T: 'static>(dto: &Dto<T>) {
    let any: Box<&dyn Any> = Box::new(&dto.data);
    if any.is::<i32>() {
        let value = any.downcast_ref::<i32>().unwrap();
        info!("i32 value: {}", value);
    } else if any.is::<Vec<i32>>() {
        let value = any.downcast_ref::<Vec<i32>>().unwrap();
        info!("Vec<i32> value: {:?}", value);
    }
}

#[test]
fn dto_test() {
    let d = Dto { data: 42 };
    call_dto(d);

    let v1 = vec![1, 2, 3];
    let d1 = Dto { data: v1 };
    call_dto(d1);
}

#[test]
fn dto_test2() {
    let d = Dto { data: 42 };
    call_dto1(&d);

    let v1 = vec![1, 2, 3];
    let d1 = Dto { data: v1 };
    call_dto1(&d1);
}

#[test]
fn demo_codec_test() {
    let mut demo_context: DemoContext<Box<dyn Codec>> = DemoContext::new();
    demo_context.add_codec("code", Box::new(JsonDemoCodec));

    let codec = demo_context.get_codec("code").unwrap();
    // let data = BincodeWrap::with_codec(332i32, codec);
    // let bytes = data.encode();

}

struct DemoContext<T> {
    codec: HashMap<&'static str, Box<dyn DemoCodec<T>>>,
}

impl <T> DemoContext<T> {
    pub fn new() -> Self {
        Self {
            codec: HashMap::new(),
        }
    }

    pub fn add_codec(&mut self, key: &'static str, codec: Box<dyn DemoCodec<T>>) {
        self.codec.insert(key, codec);
    }

    pub fn get_codec(&mut self, key: &'static str) -> Option<&Box<dyn DemoCodec<T>>> {
        let value = self.codec.get(key);
        value
    }
}

trait Codec {

    fn encode(&self) -> Vec<u8>;
    fn decode(&self, data: Vec<u8>) -> Self
    where
        Self: Sized
    ;
}

struct BincodeWrap<'a, T> {
    data: T,
    codec: Option<&'a Box<dyn DemoCodec<T>>>,
}

impl <'a, T> BincodeWrap<'a, T> {
    pub fn new(data: T) -> Self {
        Self {
            data,
            codec: None,
        }
    }

    pub fn with_codec(data: T, codec: &'a Box<dyn DemoCodec<T>>) -> Self {
        Self {
            data,
            codec: Some(codec),
        }
    }
}

impl <'a> Codec for BincodeWrap<'a, i32> {
    fn encode(&self) -> Vec<u8> {
        let codec = &self.codec;
        if let Some(codec) = codec {
            return codec.encode(&self.data);
        }
        panic!("error");
    }

    fn decode(&self, data: Vec<u8>) -> Self
    where
        Self: Sized
    {
        let codec = &self.codec;
        if let Some(codec) = codec {
            let value = codec.decode(data);
            return Self {
                data: value,
                codec: None,
            }
        }
        panic!("error");
    }
}

trait DemoCodec<T> {
    fn decode(&self, data: Vec<u8>) -> T;

    fn encode(&self, data: &T)-> Vec<u8>;
}

// trait CodecFactory {
//     fn create(&self) -> Box<dyn DemoCodec<T>>;
// }

struct JsonDemoCodec;
impl<T> DemoCodec<T> for JsonDemoCodec {
    fn decode(&self, data: Vec<u8>) -> T {
        todo!()
    }

    fn encode(&self, data: &T) -> Vec<u8> {
        todo!()
    }
}

#[test]
fn main() {
    let mut type_map: HashMap<String, String> = HashMap::new();

    // 获取类型的完整名称
    let my_struct_name = type_name::<RpcJsonCodec>().to_string();

    type_map.insert("key1".to_string(), my_struct_name);

    println!("{:?}", type_map);
    // 输出类似：
    // {"key1": "my_crate::MyStruct", "key2": "my_crate::my_module::AnotherStruct"}
}